﻿using HybridCLR;
using NL;
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace Miya.Hellow
{
    public class Hybrid : MonoBehaviour
    {
        //清单 文件的 Addressable地址..
        const string FILE_NAME_Bill = "~Bin/bill.info";

        //元数据目录..
        const string PATH_Metadata = "~Bin/Metadata";

        //热程序集..
        const string PATH_Assembly = "~Bin/Assembly";


        public string Version;

        public string Error;


        private void Awake()
        {
            DontDestroyOnLoad(gameObject);
        }
        private IEnumerator Start()
        {
            Error = "UnKnow";
            Debug.Log($"[Hybrid.Start]:......................");
            //1111111  先加载 程序集清单
            NLIni bill = null;

            var op = Addressables.LoadAssetAsync<TextAsset>(FILE_NAME_Bill);

            yield return op;

            if (op.Result != null && !string.IsNullOrEmpty(op.Result.text))
            {
                bill = new NLIni(op.Result.text, '\n');
                Debug.Log($"[Hybrid.Start]:bill \n{bill}");
            }
            else
            {
                _DoEnd($"NoBill @{FILE_NAME_Bill}"); yield break;
            }

            Version = bill["version"];

            _DoPrepared();

            yield return 0;



            //2222222   处理元数据清单...
            var metadata = bill["metadata"].AsString;

            Debug.Log($"[Hybrid.Start]:.............metadata={metadata}");

            var all = metadata.Split(';');
            foreach (var a in all)
            {
                if (string.IsNullOrEmpty(a))
                    continue;

                string filename = $"{PATH_Metadata}/{a}";
                var result = Addressables.LoadAssetAsync<TextAsset>(filename).WaitForCompletion();

                if (result == null || result.bytes == null)
                {
                    Debug.LogError($"[Hybrid.Start].LoadMetadataForAOTAssembly({filename})]:Error:result == null || result.bytes == null");
                    continue;
                }
                // 载入....元数据.... 
                var error = RuntimeApi.LoadMetadataForAOTAssembly(result.bytes, HomologousImageMode.SuperSet);

                if (error != LoadImageErrorCode.OK)
                    Debug.LogError($"[Hybrid.Start].LoadMetadataForAOTAssembly({filename})]:Error:{error}");
                else
                    Debug.Log($"[Hybrid.Start].LoadMetadataForAOTAssembly({filename})]:Success");

                yield return 0;
            }


            //333333    处理程序集清单...
            var assembly = bill["assembly"].AsString;

            Debug.Log($"[Hybrid.Start]:.............assembly={assembly}");
            all = assembly.Split(';');

            foreach (var a in all)
            {
                if (string.IsNullOrEmpty(a))
                    continue;

#if !UNITY_EDITOR // 真机环境下 加载程序集..
            string filename = $"{PATH_Assembly}/{a}";
            var result = Addressables.LoadAssetAsync<TextAsset>(filename).WaitForCompletion();

            if (result == null || result.bytes == null)
            {
                Debug.LogError($"[Hybrid.Start].LoadAssembly({filename})]:Error:result == null || result.bytes == null");
                continue;
            }

            var ass=  Assembly.Load(result.bytes);

            if (ass ==null)
                Debug.LogError($"[Hybrid.Start].LoadAssembly({filename})]:Error");
            else
                Debug.Log($"[Hybrid.Start].LoadAssembly({filename})]:Success");
                
#else
                // Editor环境下，HotUpdate.dll.bytes已经被自动加载，不需要加载，重复加载反而会出问题。
                //var assemblies = System.AppDomain.CurrentDomain.GetAssemblies()
                //    .First(w =>
                //        {
                //            return a.Contains(w.GetName().Name);
                //        });

                //var ass = Assembly.GetAssembly(typeof(int));
                //Debug.Log($"[Hybrid.Start]]GetAssemblies({a})..");
#endif
                yield return 0;
            }

            _DoEnd();
        }

        [SerializeField] protected bool Prepared = false;
        protected virtual void _DoPrepared()
        {
            Prepared = true;
            _ONPrepared?.Invoke(this);
        }
        [SerializeField] protected bool Ended = false;
        protected virtual void _DoEnd(string error = "")
        {
            Error = error; Ended = true;

            if (!string.IsNullOrEmpty(error))
            {
                Debug.LogError($"[Hybrid._DoEnd]:Error:{error}");
                ONError?.Invoke(this);
            }
            else
            {
                Debug.Log($"[Hybrid._DoEnd]:Success..");
            }


        }


        Action<Hybrid> ONError;
        public Hybrid WaitError(Action<Hybrid> on)
        {
            ONError = on;return this;
        }


        public WaitUntil WaitEnd()
        {
            return new WaitUntil(() => { return Ended; }); ;
        }

        Action<Hybrid> _ONPrepared;
        public Hybrid WaitPrepared(Action<Hybrid> on)
        {
            _ONPrepared = on; return this;
        }


    }
}

